import re

__author__ = 'YeeHin Kwok'



""" Giovanni's MicroCompiler Demo

<program>       ::=     { <id> ; <vars > <stmtlist>  }
<vars>          ::=     V { <id> ; }                       % DECLARATIONS

<stmtlist>      ::=     <stmt> { ; <stmt> }
<stmt>          ::=     P <id>  |  <id> = <expr>

<expr>          ::=     <factor> {  (+ | -)   <factor> }   % No precedence
<factor>                ::=     ID | Number

"""

import sys
import shlex

#===============================================================================
# # Lexical Analyser - the "Scanner" - Define the TokenTypes
#===============================================================================

tokenNames = \
  [ "unknownToken", "idsym", "assignsym", "leftbrace", "rightbrace",
    "varsym", "semicolon", "whilesym", "leftbracket", "rightbracket",
    "printsym", "ifsym", "equals", "lessthan", "greaterthan",
    "number", "plus", "minus", "mpy", "div", "elsesym", "declaresym", "forsym", "andsym", "elifsym", "dosym", "returnsym", "notsym",
    "continuesym", "breaksym", "nonesym", "programsym", "functionsym", "leftsquarebrace", "rightsquarebrace",
    "lessthanequal", "colon", "comma", "comment", "commentstr", "dot", " greaterthanequal", "jumpeq", "jumpne",
    "andop", "orop", "quote ", "stringsym", "arraysym", "readsym", "endfile"]

# define the tokens as variables
unknownToken, idsym, assignsym, leftbrace, rightbrace, \
    varsym, semicolon, whilesym, leftbracket, rightbracket, \
    printsym, ifsym, equals, lessthan, greaterthan, \
    number, plus, minus, mpy, div, elsesym, declaresym, forsym, andsym, elifsym, dosym, returnsym, notsym, \
    continuesym, breaksym, nonesym, programsym, functionsym, leftsquarebrace, rightsquarebrace, \
    lessthanequal, colon, comma, comment, commentstr, dot, greaterthanequal, jumpeq, jumpne, \
    andop, orop, quote, stringsym, arraysym, readsym, endfile = range(0, len(tokenNames))

#===============================================================================
class symbol:
#===============================================================================
    name = None  # String representation
    token = None;  # Corresponding token
    address = 0;  # For variables, their runtime address
    value = None  # on defined for numbers
    

    def __init__(self, name, token, value=0):
        self.name = name
        self.token = token
        self.address = 0  # for identifiers, their address
        self.value = value  # for numbers, their value


symtbl = {};  # The Symbol Table, a dictionary of symbols indexed by name

#======================================================================
# GLOBALS for output of Lexical Analyser
# Set by each call to GeToken()

token = None;  # A symbol
line = "\n"  # the complex source file as a string
charIndex = 0  # the position in the source

linenumber = 0  # The current  number

tokennum = 0
resultnum = 0

whichidentifier = None;

identifieraddress = 0;

i = 100
j = 100 
counterafter = i
counterafter1 = j


EOF = chr(0)
#======================================================================
# Run Time Code Generation Variables

varptr = 500  # Arbitrary base address of memory for variables
codeptr = 10  # Address to output next instruction (for code)


#===============================================================================
#                    Symbol Table Management Routines
#===============================================================================

#===============================================================================
def addToSymTbl (name, token):
#===============================================================================
    symtbl[name] = symbol(name, token)  # Add a new symbol to the dictionary
    return symtbl[name]


#===============================================================================
def lookup (thisName):
#===============================================================================
    "# Find a given identifier in the Symbol Table, Return the symtbl entry"
    if symtbl.has_key(thisName):  # thisName has been seen before
        return symtbl[thisName]  # return the symtbl entry
    else: return None


#===============================================================================
def initSymTbl():
#===============================================================================
    "# Initialise Symbol Table, and preload reserved words"
    addToSymTbl('var', varsym)  # VAR
    addToSymTbl('program', programsym)
    addToSymTbl('function', functionsym)
    addToSymTbl('while', whilesym)  # WHILE
    addToSymTbl('print', printsym)  # PRINT
    addToSymTbl('else', elsesym)
    addToSymTbl('elif', elifsym)
    addToSymTbl('if', ifsym)
    addToSymTbl('declare', declaresym)
    addToSymTbl('for', forsym)
    addToSymTbl('None', nonesym)
    addToSymTbl('continue', continuesym)
    addToSymTbl('read', readsym)  # READINT
    addToSymTbl('do', dosym)
    addToSymTbl('return', returnsym)
    addToSymTbl('not', notsym)



    # Now add symbols - NB only single character symbols are here
    #                      multicharacter one like ">=" are still to do
    addToSymTbl('=', assignsym)
    addToSymTbl('#', comment)
    addToSymTbl('<', lessthan)
    addToSymTbl('>', greaterthan)
    addToSymTbl('{', leftbrace)
    addToSymTbl('}', rightbrace)
    addToSymTbl('(', leftbracket)
    addToSymTbl(')', rightbracket)
    addToSymTbl('+', plus)
    addToSymTbl('-', minus)
    addToSymTbl(';', semicolon)
    addToSymTbl('break', breaksym)
    addToSymTbl('*', mpy)
    addToSymTbl('/', div)
    addToSymTbl('[', leftsquarebrace)
    addToSymTbl(']', rightsquarebrace)
    addToSymTbl(':', colon)
    addToSymTbl(',', comma)
    addToSymTbl('.', dot)
    addToSymTbl('==', jumpeq)
    addToSymTbl('!=', jumpne)
    addToSymTbl('&&', andop)
    addToSymTbl('||', orop)
    addToSymTbl('"', quote)
    addToSymTbl(EOF, endfile)


#===============================================================================
#                       Scanner Diagnostics
#===============================================================================
def printToken(tok):
#===============================================================================
    " - display the specified token."
    if tok.token == idsym:
       print "Token = %10s,  %-10s  adr = %3d, val = %d" % \
             (tokenNames[tok.token], tok.name, tok.address, tok.value)
    elif tok.token == number:
       print "Token = %10s  %d" % (tokenNames[tok.token], tok.value)
    else:
       print "Token = %10s" % tokenNames[tok.token]

#==============================?=================================================
def dumpSymTbl():
#===============================================================================
    """ Dump all the tokens in the symboltable """
    print("# *** Symbol Table ***")
    for name in symtbl.keys():  # keys is a list of the names (printable form of tokens)
        tok = symtbl[name]
        if tok.token == idsym:
            print("#"),
            printToken(tok)

#===============================================================================
def getch():
#===============================================================================
    global line
    global charIndex
    global linenumber

    while True:
        if charIndex < len(line):  # See if used up current line
            ch = line[charIndex]  # if not, get character
            charIndex = charIndex + 1  # & move pointer for next time
        else:
            
            # line = f.readline()
            # if  line == "": line = EOF
            dumpSymTbl()
            print "#End of File"
            print "#--> ",
            line = raw_input() + "\n"  # read new line, adding \n so it's like f.readline()
#            line = srcfile.read()
            charIndex = 0  # & reset character pointer
            linenumber = linenumber + 1
            continue

        if ch == "\n":
            ch = " "

        if ch == '?':
            dumpSymTbl()
            continue
        return ch

#===============================================================================
def ungetch():
#===============================================================================
    """ Unget the next character peeked at when building variables, numbers
        and when distinguishing between >= and > ...
    """
    global charIndex;
    charIndex = charIndex - 1;

#===============================================================================
def getoken():
#===============================================================================
    """ GETOKEN - Put next token into the global TOKEN """
    global token
    global i
    global m
    global counterafter
    global counterafter1
    x = 0
    ch = getch()  # skip whitespace
    while ch in ["\t", " ", "\n"]:
        ch = getch()

    # If ch is alphabetic then this is start of reserved word or an identifier
    if ch.isalpha():  # Letter therefore it's either identifier or reserved word
        name = ""
        while ch.isalpha() or ch.isdigit() or ch == "_":
            name = name + ch
            ch = getch()

        ungetch()  # let terminator be used next time

        token = lookup(name)  # See if token's known
        if token is None:  # if not
            token = addToSymTbl(name, idsym)  #   add as 'idsym'-IDENTIFIER

        return  # we've set token.token to either id or tokentype of reserved word

    elif ch in ["{", "}", "(", ")", "[", "]", "+", "-", "*", "/", ";", ",", ":", EOF]:
        token = lookup(ch)  # preloaded with appropriate token

    elif ch.isdigit():

        # In the real version, build number and don't forget to end with ungetch()
        while(ch.isdigit() == True):
            x = str(x) + str(ch)
            ch = getch()
        ch = ungetch()

        token = symbol(x, number, value=int(x))  # simplistic SINGLE DIGIT Ascii to Binary
        return

    # elif ch == "-":
    #     x = ""
    #     no =""
    #     ch = getch()
    #     if ch.isdigit() ==True:
    #         while ch.isdigit():
    #             x = str(x) + str(ch)
    #             ch = getch()
    #
    #         ch = ungetch()
    #
    #         no = "-" + str(x)
    #
    #         token = symbol(no, number, value = int(no))

    elif ch == '#':
        str1 = ""
        ch = getch()

        while(ch != " "):
            str1 = str(str1) + str(ch)

            ch = getch()

        ch = getch()

        token = symbol(str1, commentstr, value=str(str1))  # simplistic SINGLE DIGIT Ascii to Binary
        print("#comment: " + str(str1))
        return
    
    elif ch == '"':
        a = ""
        
        ch = getch()
        
        counterafter1 = counterafter
                    
        i = counterafter
        if counterafter != 100:
            counterafter = counterafter + 4;
            counterafter = i
            
        
        while (ch != '"'):
            
            a = str(a) + str(ch)
            if ch != " ":
                b = "'" + ch + "'"
            emit(i, "constant", b)
            ch = getch()
            i = i + 1 
        emit(i, "constant", 13)
        emit(i + 1, "constant", 0)
        emit(i + 2, "return", '')
        ch = getch()
        counterafter = i + 3

        token = symbol(a, stringsym, value=str(a))  # simplistic SINGLE DIGIT Ascii to Binary
        
        
#        printMsg()
        return
    elif ch == "<":

        ch = getch()
        if ch == "=":
            lt = ""
            lt = "<" + "="

            token = symbol(lt, lessthanequal, value=str(lt))  # simplistic SINGLE DIGIT Ascii to Binary
            return
        else:
            ch == ungetch()
            token = symbol("<", lessthan, value="<")  # simplistic SINGLE DIGIT Ascii to Binary
            return
    elif ch == "!":
        ne = ""
        ch = getch()
        if ch == "=":
            ne = "!" + "="

            token = symbol(ne, jumpne, value=str(ne))  # simplistic SINGLE DIGIT Ascii to Binary
            return
        else:
            ch == ungetch()
            token = symbol("!", NOT , value="!")  # simplistic SINGLE DIGIT Ascii to Binary
            return
    
    elif ch == "=":

        eq = ""
        ch = getch()
        if ch == "=":
            
            eq = "=" + "="

            token = symbol(eq, jumpeq, value=str(eq))  # simplistic SINGLE DIGIT Ascii to Binary
            return
        else:
            ch == ungetch()
            token = symbol("=", assignsym, value="=")  # simplistic SINGLE DIGIT Ascii to Binary
            return
        
    elif ch == ">":

        gt = ""
        ch = getch()
        if ch == "=":
            gt = ">" + "="

            token = symbol(gt, greaterthanequal, value=str(gt))  # simplistic SINGLE DIGIT Ascii to Binary
            return
        else:
            ch == ungetch()
            token = symbol(">", greaterthan, value=">")  # simplistic SINGLE DIGIT Ascii to Binary
            return
    else:
        print "Unknown character -->%s<- decimal %d" % (ch, ord(ch))
        sys.exit(1)  # Abort Compilation

#======================================================================
# THE GRAMMAR

# <program>       ::=     { <id> ; <vars > <stmtlist>  }
# <vars>          ::=     var { <id> ; }                    % DECLARATIONS
# <array>         ::=     [<expr>]

# <stmtlist>      ::=     <stmt> { ; <stmt> }
# <stmt>          ::=     print <id>
#                         <id> = <expr>

# <expr>          ::=     <term> {  (+ | - )   <term> }
# <term>          ::=     <factor> { (*|/) factor}
# <factor>        ::=     [+/-] ID | Number | expression 

#======================================================================
#                  Centralised Parser Error Message handler
#======================================================================


#===============================================================================
def error (msg):
#===============================================================================
    print line
    print "-" * charIndex, "^"
    print("Error on  %d - %s\n" % (number, msg))
    printToken(token)
    print("\n")

#===============================================================================
def emit (memadr, opcode, parameter):
#===============================================================================
    """EMIT CODE - Emit a  of code with a Parameter
    if first arg is zero - (the memory address), use and incr CODEPTR"""
    global codeptr

    if (memadr == 0):
        memadr = codeptr
        codeptr = codeptr + 1
    print "%6d  %-8s %-7s" % (memadr, opcode, parameter)

#======================================================================
# VARIABLE DECLARATIONS
#   <vars>              ::=     V { <id> ; }
#    <vars>     ::=    <id>[array]
#===============================================================================
def vars() :
#===============================================================================

    ta = 0
    tn = []
    global varptr;

    getoken();

    if token.token == idsym:
        ta = token.address
        tn = token.name
        getoken()

        if token.token == leftsquarebrace:

            getoken()
            if token.token == number: #number
                
                print("#The address for "+ str(tn)+ " are ")
                symtbl[tn].address = varptr;
                emit(0, "constant", varptr)
                while (token.value != 0):
#                    print("#address at " + str(varptr))
                    emit(0, "constant", token.value)
                    varptr = varptr + 1
                    token.value= token.value-1
                array()

            elif token.token == idsym:  #id 
#                getoken()
                expression()
                getoken()
                
            if token.token == rightsquarebrace:
                    getoken()
                
        else:
            if ta != 0:
                print("%c already declared\n", tn);
                # assignStmt()
            else:
                symtbl[tn].address = varptr;
                varptr = varptr + 1
#                emit(0, "load", varptr)

    if token.token == assignsym:
        getoken()

        expression()
    
    if token.token == number:
        emit(0, "loadv", token.value)
        emit(0, "add", 11)
        emit(0, "store", 1)
        getoken()
    
    if token.token == rightbracket:
        getoken()
    
    if token.token == comma:
        vars()
    elif token.token == semicolon : getoken()
    
    else: error("comma or semicolon expected in declaration")

    
#===============================================================================
def array():
#    [expression]
#===============================================================================
    global array;
    
    expression()
    
#===============================================================================
def parameters():
#===============================================================================
    vars()
#======================================================================
# STMTLIST
# <stmtlist>  ::= <stmt> { ; <stmt> }

#===============================================================================
def stmtList():
#===============================================================================
    stmt()

    while (token.token != rightbrace):
        stmt()


#======================================================================
# STMT

#===============================================================================
def stmt():
#===============================================================================
    """  <stmt> ::=  print <expression|string>| read <vars>  |  <id> = <expression> | 
        if <condition> <stmt> [else <stmt>]| while <condition> <stmt>|
        <stmtList>  | do <stmsList> forever | break | continue
    """
    global codeptr

    thisStmtAdr = codeptr  # Jump DEMO - not part of Stmt
#    if token.token == arraysym:
 #       array()
    if token.token == vars:
        expression()
        
    if token.token == ifsym:
        ifStmt()
        
    if token.token == elsesym:
        elseStmt()       
            
    elif token.token == whilesym:
        whileStmt() 
        
    elif token.token == stmtList:
        stmtList()
        
    elif  token.token == printsym:
        printStmt()
        
    elif token.token == readsym:
        readStmt()
    
    elif token.token == dosym:
        doStmt()
    
    elif token.token == breaksym:
        factor()
            
    elif token.token == continuesym:
        continueStmt()
                
    elif token.token == number:
        expression()
        
    elif token.token == idsym:
        assignStmt()
    
    elif token.token == functionsym:
        function()

    elif token.token == returnsym:
        returnStmt()

    elif token.token == stringsym:
#        print(str(token.name))
        printMsg()
        getoken()
    
    elif  token.token == leftbracket or token.token == rightbracket or token.token == leftbrace or token.token == rightbrace or token.token == rightsquarebrace or token.token == assignsym:
        getoken()

    elif token.token == commentstr or token.token == breaksym:
 #       print(str(token.name))
        getoken()

    elif token.token == lessthan or token.token == greaterthan or token.token == lessthanequal or token.token == greaterthanequal or token.token == jumpeq or token.token == jumpne:
        relational_op()
       
    elif  token.token == semicolon or token.token == comma:
        getoken()

    else:
        error("Expected start of a statement")

    # emit (0, "return", thisStmtAdr)   Jump DEMO  need in break program

#===============================================================================
def printStmt():
#===============================================================================
    """   <printStmt> ::= print <expression|string>"""

    global idaddress
    
    getoken()  # skip "print"
    getoken()
    
    if token.token == idsym:
        print("#This is a id")
        function()
        emit(0, "writeint", 503)
    if token.token == stringsym:
        printMsg()
#        emit(0, "writeint", 501)
        if token.token == stringsym:
            printMsg()
            
            if token.token == idsym:
                function()
                emit(0, "writeint", 503)
                getoken()

        if token.token == idsym:
            emit(0, "writeint", 501)
            emit(0, "writeint", 502)
#            emit(0, "halt", '')
            getoken()
    else:    
        emit(0, "writeint", 501)
        getoken()
#        emit(0, "writeint", 7)
        
    
#===============================================================================
def printMsg():
#===============================================================================
    """   <printMsg> ::= printMsg <expression>"""
 #   print("#"+str(counterafter)+ " counterafter")
 #   print("#"+str(counterafter1)+ " counterafter1")
       
        
    emit(0, "loadv", counterafter1)
    emit(0, "store", 1)
    emit(0, "call", 400)
    emit(400, "load-Ind", 0)
    emit(401, "jumpeq", 405)
    emit(402, "writech", 0)
    emit(403, "increment", 1)
    emit(404, "jump", 400)
    emit(405, "return", '')
    getoken()
    

#===============================================================================
def readStmt():
#===============================================================================
    """   <readStmt> ::= read <vars>"""
    
    getoken()
       
    emit(0, "readint", 7)
    emit(0, "load", 7)
    emit(0, "store", 500)
    getoken()
        
#===============================================================================
def assignStmt():
#===============================================================================
    """
        <id> = <expression>
    """
    global tokennum
    global resultnum
    global whichidentifier
    
    whichidentifier = token.name  # Remember which ID on Left
    whichidaddress = token.address
#    print("#whichidentifier: " +str(whichidentifier))
    
    getoken()  # Get token after identifier
    if token.token == assignsym:
        getoken()
    elif token.token == leftsquarebrace:
        vars()
    elif token.token == leftbrace:
        vars()
    elif token.token == jumpeq:
        getoken()
    elif token.token == jumpne:
        getoken()
    elif token.token == rightbracket:
        getoken()
    elif token.token == lessthanequal:
        getoken()
    elif token.token == idsym:
        getoken()
    elif token.token == leftbracket:
        getoken()
  
    elif token.token == comma:
        getoken()
    elif token.token == greaterthanequal:
       getoken()
    elif token.token == semicolon: 
        getoken()
    else:
        error("Expected = in assignment statement")    
#    print("#Store value")
    
    expression()
     
    passtoken = token.value
 #   print(str(tokennum))
    symtbl[whichidentifier].value = tokennum
    emit(0, "store", whichidaddress)
    getoken()
    
    
    
#===============================================================================   
def ifStmt():
# if-then-else
#===============================================================================
    """   <ifStmt> ::= if <expression>"""
    
    print("#IFSmt")
    getoken()  # skip "if"  
    condition()
    stmt()
    
#===============================================================================
def elseStmt():
# if-then-else
#===============================================================================
    """   <elseStmt> ::= else <expression>"""
    
    print("#ElseSmt")
#    emit(200, "jump", 47) # less than 2 go to else
    getoken()
    stmt()
#    emit(0, "halt", '')
#===============================================================================
def whileStmt():
#===============================================================================
    """   <whileStmt> ::= while (condition)statement"""
    
#    emit(0, "load", 201)
#    emit(0, "store", 502)
    getoken()
    expression()  # num>0
    stmtList()
    stmtList()
    emit(0, "jump", 122)
    

#===============================================================================
def doStmt():
#===============================================================================
    getoken()
    expression()
    stmt()

#===============================================================================
def returnStmt():
#===============================================================================
    
    getoken()
    
    if token.token == leftbracket:
        getoken()
    
    if token.token == idsym:
        
        emit(600, "add", 505)
    
        emit(601, "store", 503)
    
        emit(602, "return", '')
        
    if token.token == rightbracket:
        getoken()
    
    if token.token == semicolon:
        getoken()

#===============================================================================
def condition():
#===============================================================================
    if token.token == notsym:
        emit(0, "Not", '')
        getoken()
    
    conditionalexp()
    

#===============================================================================
def conditionalexp():
#===============================================================================   
    expression()
    
    relational_op()
    
    expression()

#===============================================================================
def relational_op():
#===============================================================================  
    
     if token.token == lessthan or token.token == greaterthan or token.token == lessthanequal or token.token == greaterthanequal or token.token == jumpne or token.token == jumpeq:
        op = token  # remember -
        getoken()  # skip past -
        term()
            
        if op.token == lessthan:
#            emit(0, "load", 501)
            emit(0, "compare", 500)
            emit(0, "jumplt", 43)
            
        elif op.token == greaterthan:
#            emit(0, "load", 200)
            emit(0, "compare", 504)
            emit(0, "jumpgt", 122)
            emit(0, "jump", 130)
            
        elif op.token == lessthanequal:
#            emit(0, "load", 200)
            emit(0, "compare", 500)
            emit(0, "jumplt", 43)
            emit(0, "jumpeq", 43)
#            emit(300, "writeInt", 502)
            
        elif op.token == greaterthanequal:
#            emit(0, "load", 200)
            emit(0, "compare", 500)
            emit(0, "jumpgt", 43)
            emit(0, "jumpeq", 43)
#            emit(300, "writeInt", 502)

        elif op.token == jumpne:
            emit(0, "load", 205)
            emit(0, "compare", 502)
            emit(0, "jumpne", 310)
            emit(0, "writeInt", 0)
            emit(0, "halt", 0)
#            emit(310, "writeInt", 502)

        elif op.token == jumpeq:
#            emit(0, "load", 200)
            emit(0, "compare", 504)
            emit(0, "jumpeq", 0)
#            emit(0, "halt", '')
#           emit(0, "jump", 131)

    
#===============================================================================
def expression():
#===============================================================================
    """
       Leaves result in ACC at runtime
       Use addresses 999 & 998 as Temporary variables

       <expression> ::=  <factor> {  (+ | -)  <factor> } <- wrong
       <expression> ::=  <term> {  (+ | -)  <term> }
    """
    global whichidentifier
    global idaddress
    global idvalue     
    
    if whichidentifier == None:
        getoken()
    else:
        idaddress = symtbl[whichidentifier].address 
        idvalue = symtbl[whichidentifier].value 

    if token.token == leftbracket: 
        getoken()
        term()
        while token.token == plus or token.token == minus:
            op = token  # remember -
            getoken()  # skip past -
            term()
        
            if op.token == plus:
                emit(0, "add", 501)
#                emit(0, "store", 500)
#                emit(0, "writeInt", 500)
        
            elif op.token == minus:  # Subtract - have to swap operand order
                emit(0, "load", 501)
                emit(0, "subtract", 1)
                emit(0, "store", 501)
                emit(0, "store", 1)
            
            getoken()
            
    
    term()
#    print("term 1" + str(factor()))
    
## 1st start==============================================================================    
    while token.token == plus or token.token == minus:
        op = token  # remember -
        getoken()  # skip past -
        # emit(0, "store", 997) # Save current result
        term()
#        print("term 2" + str(term))
#        print("#whichidentifier " + whichidentifier)
        
        
        if op.token == plus:
            emit(0, "loadv", idvalue)
            emit(0, "add", 1)
#            emit(0, "store", idaddress)
#            emit(0, "store", 500)
#            emit(0, "writeInt", 500)
        
        elif op.token == minus:  # Subtract - have to swap operand order
            emit(0, "load", 500)
            emit(0, "subtract", 1)
            emit(0, "store", idaddress)
            emit(0, "store", 1)
            
            
#            emit(0, "writeInt", 501)
   
        

#===============================================================================
def term():
#===============================================================================
    """ 
        term::= factor {(*|/) factor}
    """
    global idaddress
    
    factor()
    
    while token.token == mpy or token.token == div:
        op = token  # remember -
        getoken()  # skip past -
        factor()
        
        if op.token == mpy:
            emit(0, "mpy", 1)
#            emit(0, "store", 205)
            emit(0, "store", 502)
            emit(0, "store", 1)

            while token.token == mpy:
                
                op2 = token  # remember -
                getoken()  # skip past -
                factor()
                
                emit(0, "mpy", 502)
#                emit(0, "store", 205)
                emit(0, "store", idaddress)
                emit(0, "store", 1)
        
        elif op.token == div:
 #           emit(0, "load", 502)
            emit(0, "div", 504)

         


#===============================================================================
def factor():
#===============================================================================
    """
      # FACTOR() - leaves result in ACC at runtime
          <factor> ::= [+|-] identifier | number | (expression)
    """
    global tokennum
    global whichidentifier
    global idaddress
    global idvalue     

      
    #   [+|-] number       
    if token.token == plus:
        getoken()
        if token.token == number:
            emit(0, "loadv", token.value)
            emit(0, "store", 200 + token.value)
            getoken()
            
    # - (unary)
    elif token.token == minus:
        getoken()
        if token.token == number:
            emit(0, "loadv", 0 - token.value)
            emit(0, "store", 200 + token.value)
            getoken()
    
    elif token.token == number:
        emit(0, "loadv", token.value)
        emit(0, "store", 1)
        tokennum = token.value
        getoken()
            
     #    identifier
    elif token.token == idsym:
        

#        print("#token address " + str(token.address))
#        print("#token value " + str(token.value))
        emit(0, "load", token.address)
        getoken()
        
    #    (expression)
    elif token.token == leftbracket:
        expression()
    
    elif token.token == lessthan or token.token == greaterthan or token.token == lessthanequal or token.token == greaterthanequal or token.token == jumpeq or token.token == jumpne:
        relational_op()
                
    elif token.token == stringsym:  #################
        print("#String: " + str(token.name))
#       printMsg()
        printStmt() 
        getoken()
            
    elif token.token == commentstr or token.token == rightbracket or token.token == leftsquarebrace or token.token == rightsquarebrace:           
#        print ("#Comment: " + str(token.name))
        getoken()
    

    elif token.token == breaksym:
        emit(0, "halt", '')
        getoken()
    
    elif  token.token == semicolon or token.token == comma:
        getoken()
        
    elif  token.token == leftbrace:
       getoken()

    elif token.token == rightbrace:
         print("")
         
    elif token.token == ifsym:
        ifStmt()
        
    elif token.token == printsym or token.token == returnsym or token.token == functionsym:
        getoken()
    
    else:
        error("Start Of Factor Expected")
         

#===============================================================================
def function():
#===============================================================================
    if token.token == functionsym:
        getoken()
        
    if token.token == idsym:
        getoken()
    
    if token.token == leftbracket:
        getoken()
        
    if token.token == idsym:
        parameters()        
        
    elif token.token == number:
        print("#"+str(token.value))
        emit(0, "loadv", token.value)
        emit(0, "call", 600)
        getoken()
    else:
        error("Function error : No_parameter_input_for_function")
    
    if token.token == rightbracket:
        getoken()        
        
    if token.token == declaresym :
        vars()
        
    if token.token == varsym :
        vars()
    
    if token.token == semicolon:
        getoken()
    
    if token.token == leftbrace:
        getoken()
     
    
    if token.token == plus:
        expression
        getoken()
    stmt()
#    emit(0, "call", 600)
#    returnStmt()
#    emit(0, "call", 600)   

    if token.token == semicolon:
        getoken()
    
        
    if token.token == rightbrace:
        print ("#---Function Finished---")

#===============================================================================
def program():
#===============================================================================

    if token.token == leftbrace:
        getoken()

    if token.token == programsym:

        getoken()
    else: error("Program start with 'program' keyword")

    if token.token == idsym:

        getoken()

    if token.token == semicolon:

        getoken()

    if token.token == declaresym :
        vars()
    if token.token == varsym :
        vars()
    
    if token.token == functionsym:
        function()
    
    if token.token == leftbrace:
        getoken()

    stmtList()
    
    stmtList()
    
    if token.token == rightbrace:
        print "#***Compilation Finished****"




#======================================================================
def main():
#======================================================================
    global line
    global srcfile
    global charIndex

    initSymTbl()


    with open("test.txt") as srcfile:
#        out1file = open('output.obj','w')
        line = srcfile.read()
        # out1file.write("hello")
       #   print line

    charIndex = 0

    debugScanner = False
    if debugScanner:  # Scanner Test Routine - Read a line and display the tokens
       getoken()
       while token.token is not None:  # Skeleton for testing Scanner
           printToken(token)
#           y = str(token)
#           out1file.write(y)
           getoken()
       sys.exit(1)
    else:
        getoken()  # Parse Program according to the grammar
        program()


#===============================================================================
# Main Compiler starts here
#===============================================================================

print "#Microcompiler.py v0.2"
emit(0, "load", 9)
main()

"""
srcfile = open('tiny_1.txt', 'r')
lexer = shlex.shlex(srcfile)
for token in lexer:
    print repr(token)
"""

# getoken()


#=======================================================================
# *** That's it folks - written by Giovanni Moretti - April 27, 2011 ***
#=======================================================================

